import numpy as np
import time
from tqdm import trange
from cion.core.hardware.rtmq.CION_Sequencer import *


### Examples
def inc_timer_and_trigger():
    pwm_test = NewExperiment()
    with pwm_test:
        with AutoBubble(0):
            TTL_Stage(0, 0xFFFFFFFF, 0.1)
            R.R2 = 0
            with LoopForever():
                TTL_Stage(2, R.R2, 200000000)
                ExtTrigger()
                R.R2 += 1
    Run(pwm_test)

def inc_timer_or_trigger():
    pwm_test = NewExperiment()
    with pwm_test:
        with AutoBubble(0):
            TTL_Stage(0, 0xFFFFFFFF, 0.1)
            R.R2 = 0
            with LoopForever():
                Set(R.LED, R.R2)
                ASM(["LDH - -  TR0  200000000",
                    "LDL - -  TR0  200000000"])
                time = R.TR0
                Pass()
                Set(R.TIM, time)
                Set(R.NOW, R.WCK + time)
                ExtTrigger()
                R.R2 = ADD(R.R2, 1)
    Run(pwm_test)

def inc_if():
    pwm_test = NewExperiment()
    with pwm_test:
        with AutoBubble(0):
            R.R2 = 0
            with LoopForever():
                TTL_Stage(2, R.R2, 200000000)
                R.R2 = ADD(R.R2, 1)
                with If(R.R2 == 0xF):
                    R.R2 = 2
    Run(pwm_test)

def inc_else():
    pwm_test = NewExperiment()
    with pwm_test:
        with AutoBubble(0):
            R.R2 = 0
            with LoopForever():
                TTL_Stage(2, R.R2, 200000000)
                with If(R.R2 == 0xF):
                    R.R2 = 2
                with Else():
                    R.R2 += 1
    Run(pwm_test)

def inc_subroutine():
    pwm_test = NewExperiment()
    with pwm_test:
        with AutoBubble(0):
            with Subroutine("dec", [R.R2]):
                with Repeat(R.R2, 10):
                    TTL_Stage(2, 9 - R.R2, 100000000)
            R.R2 = 0
            with LoopForever():
                TTL_Stage(2, R.R2, 200000000)
                R.R2 += 1
                with If(R.R2 == 5):
                    Call("dec")
                with Elif(R.R2 == 0x10):
                    R.R2 = 0
    Run(pwm_test)

def read_err():
    test = NewExperiment()
    with test:
        with AutoBubble(0):
            SerialSend(eval("R.ERR"))   # should return 0

            ASM(["LDL H -  TR0 1"])     # set the timer with the shortest time
            time = R.TR0
            Pass()
            Set(R.TIM, time)
            Set(R.NOW, R.WCK + time)
            Pass(20)                    # dummy instructions
            SerialSend(eval("R.ERR"))   # should return 4, representing timer overflow
            SerialSend(eval("R.ERR"))   
    print(Run(test, 3))

def branch():
    f = NewExperiment()
    with f:
        with Repeat (R.R3, 3):
            R.LED = 7
            with Repeat (R.R2, 10):
                TTL_Stage(0, 0, 0.1)
                Cntr_ON([0])
                with Repeat(R.R0, 200):
                    TTL_Stage(0, 0xFFFFFFFF, 1000000)
                    TTL_Stage(0, 0, 1000000)
                Cntr_OFF([0])
                #with If (R.C00 > 10000):
                with If (R.R2 > 5):
                    R.LED = 1
                with Else():
                    R.LED = 15
    Run(f)
####

def jump_test():
    f = NewExperiment()
    with f:
        R.LED = 1
        with Repeat(R.R1, 10):
            Cntr_ON([0])
            with Repeat(R.R0, 8000000):
                TTL_Stage(0, 0xFFFFFFFF, 1)
                TTL_Stage(0, 0, 1)
            Cntr_OFF([0])
            with If(R.R1 < 5):
                R.LED = 7
                Jump("end")
            JumpIf(R.C00 > 4000000, "tlabel")
            Label("flabel")
            R.LED = 3
            Jump("end")
            Label("tlabel")
            R.LED = 15
            Label("end")
    Run(f)

current_port = "COM7"

def run_Sequence(sequence, repeat, threshold, port = "COM7"):
    ## Currently we only permit feedforward control, e.g., if-then-else branches.
    ### WhileLoop is not supported yet, but will be finished soon.
    global seqr
    global current_port
    #print(current_port)
    #print(seqr)
    if current_port != port and seqr != None:
        current_port = port
        seqr = UARTDevice([port], 4000000)
    f = NewExperiment()
    end_time = set()
    t_branch_time = set()
    f_branch_time = set()
    iter_times = 0
    for pulse_item in sequence:
        if pulse_item[3] != None:
            if pulse_item[3] != 'Pure_detection':
                t_time = pulse_item[3][1].get('t')
                if t_time != None:
                    t_branch_time.add(t_time[0])
                    end_time.add(t_time[1])    
                f_time = pulse_item[3][1].get('f')
                if f_time != None:
                    f_branch_time.add(f_time[0])
                    end_time.add(f_time[1])   
                iter_times = pulse_item[3][1].get('iter_times')
    final_time = max(end_time)
    #print(t_branch_time) 
    #print(f_branch_time) 
    with f:
        cnt = 0
        R.LED = 3
        R.R2 = 0
        ll = len(sequence)
        print("start")
        with Repeat (R.R0, repeat):
            R.LED = 3
            while cnt < ll-1:
                pulse_item = sequence[cnt]
                #print("ttl time {} to {}".format(pulse_item[2][0], pulse_item[2][0]+pulse_item[2][1]))
                if pulse_item[2][0] == final_time:
                    Label('final_time')
                    print('final_time')
                if pulse_item[2][0] in t_branch_time:
                    Label("tlabel")
                    print('tlabel')
                if pulse_item[2][0] in f_branch_time:
                    Label("flabel")
                    print('flabel')
                if pulse_item[3] != None:
                    if pulse_item[3] != 'Pure_detection':
                        Label('branch')
                        print('branch')
                if pulse_item[3] != None:
                    Cntr_ON([0])
                #cycles = int(pulse_item[2][1]*200)
                cycles = int(pulse_item[2][1]*20000)
                print("cycles", cycles)
                if cycles > 0:
                    #TTL_Stage(0, pulse_item[0], cycles)
                    with Repeat (R.R1, cycles/2):
                        TTL_Stage(0, pulse_item[0], 1)
                        TTL_Stage(0, 0, 1)
                if pulse_item[3] != None:
                    Cntr_OFF([0])
                    print('after detection')
                    #print("R.C{:02}".format(0))
                    RC = eval("R.C{:02}".format(0))
                    if pulse_item[3] == 'Pure_detection':
                        RC = eval("R.C{:02}".format(0))
                        SerialSend(RC)
                        cnt += 1
                        print("Pure_detection")
                    else:
                        cnt += 1
                        branch_item = pulse_item[3]
                        assert isinstance(branch_item[0], int)
                        R.R2 = ADD(R.R2, 1)
                        with If (RC > threshold):
                            R.LED = 1
                            Jump("tlabel")
                        with Else():
                            R.LED = 15
                            Jump("flabel")
                else:
                    cnt += 1
                if (pulse_item[2][0]+pulse_item[2][1]) in end_time:
                    with If (R.R2 < iter_times):
                        Jump('branch')
                    with Else():
                        Jump("final_time")
            print("end")
        R.LED = 3
    Run(f)

    



if __name__ == '__main__':
    #PWM_Test()
    #inc_timer_and_trigger()
    #CntrTTL(0, range(8), 20000)
    read_err()
    #branch()
    #TrigTest()
    #read_err()
